//=========================================================================
// Copyright (C) 2024 The C++ Component Model(COMO) Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=========================================================================

#ifndef _RELIABLE_UDP_H_
#define _RELIABLE_UDP_H_

#include <stdint.h>
#include <stdbool.h>

#define COMO_FUNCTION_SAFETY_RTOS

#define MAX_PACKAGE                 (0x7fff - 4)
#define MAX_SEND_AGAIN_ARRAY_SIZE   32
#define MAX_PACKAGE_BUFFER_SIZE     10

//#define GENERAL_PACKAGE 512
#define GENERAL_PACKAGE 128

typedef struct tagRudpPackage {
    struct tagRudpPackage *next;
    char                  *buffer;
    int                    sz;
} RudpPackage;

struct rudp_message {
    struct rudp_message *next;
    uint8_t             *buffer;
    int                  sz;
    int                  cap;
    int                  id;
    int                  tick;
};

struct rudp_message_queue {
    struct rudp_message *head;
    struct rudp_message *tail;
};

#ifdef COMO_FUNCTION_SAFETY_RTOS
struct rudp_array {
    int cap;
    int n;
    int a[MAX_SEND_AGAIN_ARRAY_SIZE];
};
#else
struct rudp_array {
    int cap;
    int n;
    int *a;
};
#endif

#define MAX_PACKAGE_LENGTH  (MAX_PACKAGE + sizeof(struct rudp_message))

typedef struct tagRudp {
    struct rudp_message_queue send_queue;      // user packages will send
    struct rudp_message_queue recv_queue;      // the packages recv
    struct rudp_message_queue send_history;    // user packages already send

    RudpPackage *send_package;                 // returns by RudpUpdate

    struct rudp_message *free_list;            // recycle message struct
    struct rudp_array send_again;              // package id need send again

    int corrupt;
    int current_tick;
    int last_send_tick;
    int last_expired_tick;
    int send_id;
    int recv_id_min;
    int recv_id_max;
    int send_delay;
    int expired;

#ifdef COMO_FUNCTION_SAFETY_RTOS
    char packageBuffer[MAX_PACKAGE_BUFFER_SIZE][MAX_PACKAGE_LENGTH];
    bool usedBuffer[MAX_PACKAGE_BUFFER_SIZE];
#endif
} Rudp;

Rudp *RudpNew(Rudp *rudp, int send_delay, int expired_time);

void RudpDelete(Rudp *);

// return the size of new package, 0 where no new package
// -1 corrupt connection
int RudpRecv(Rudp *U, char *buffer);

// send a new package out
int RudpSend(Rudp *U, const char *buffer, int sz);

// should call every frame with the time tick, or a new package is coming.
// return the package should be send out.
RudpPackage *RudpUpdate(Rudp *U, const void *buffer, int sz, int tick);

#endif
